#ifndef _M_SELECT_H_
#define _M_SELECT_H_
#include"tcpsocket.hpp"
#include"sys/select.h"
#include<vector>
using namespace std;
class Select{
    private:
        fd_set _rfds;
        int _max_fd;
    public:
    Select():_max_fd(-1){
        FD_ZERO(&_rfds);
    }
    //添加描述符的监控
    void Add(TcpSocket &sock){
        //1.添加监控
        FD_SET(sock.Fd(),&_rfds);
        //2.重新设置最大的描述符
        _max_fd=_max_fd>sock.Fd()?_max_fd:sock.Fd();
    }
    //移除描述符的监控
    void Del(TcpSocket &sock){
        //从集合中移除指定描述符
        FD_CLR(sock.Fd(),&_rfds);
        //更新最大描述符-移除后，从max_fd开始向前判断，还在集合中的就是最大的
        for(int i=_max_fd;i>=0;i--){
            if(FD_ISSET(i,&_rfds)){
                _max_fd=i;
                break;
            }
        }
    }
    //开始监控，返回就绪的套接字数组
    bool Wait(vector<TcpSocket> &ready,int timeout=3){
        //1.定义时间结构
        struct timeval tv={.tv_sec=timeout,.tv_usec=0};
        //2.开始监控
        fd_set tmp=_rfds;
        int ret=select(_max_fd+1,&tmp,nullptr,nullptr,&tv);
        if(ret<0){
            perror("select error");
            return false;
        }
        else if(ret==0){
            cout<<"select timeout!\n";
            ready.clear();
            return true;
        }
        //3.遍历集合，找出就绪的描述符
        for(int i=0;i<=_max_fd;i++){
            if(FD_ISSET(i,&tmp)){
                TcpSocket sock(i);
                ready.push_back(move(sock));
            }
        }
        return true;
    }
};
#endif